/**
 * Copyright  2025, Hai Yue Xing He  ZHAO LIMIN
 * 
 * @author        ZHAO LIMIN
 * @version       1.0.1
 * @since         2025-04
 * 抛物线轨迹工具类
 */
import {Vec2 } from "cc";                       //用于数学运算
import {HYXH_GRAVITY} from "../HYXHCommon";      //常量

                    

class HYXHParabolaUtils {
    /**
     * 计算抛物线轨迹点 2D
     * 
     * @param startPoint 起始点 类型cc.Vec2
     * @param endPoint 结束点   类型cc.Vec2
     * @param height 抛物线高度 (绝对值)
     * @param progress 进度 (0-1)
     * @returns 当前进度对应的坐标点
     */
    static calculatePoint_vec2(
        startPoint: Vec2,
        endPoint: Vec2,
        height: number,
        progress: number
    ): Vec2 {
        if (progress < 0) progress = 0;
        if (progress > 1) progress = 1;

        // 计算中间控制点（顶点）
        const controlX = (startPoint.x + endPoint.x) / 2;
        const controlY = Math.min(startPoint.y, endPoint.y) - Math.abs(height);

        // 使用二次贝塞尔曲线公式计算坐标
        const x = this.calculateBezier(startPoint.x, controlX, endPoint.x, progress);
        const y = this.calculateBezier(startPoint.y, controlY, endPoint.y, progress);

        return new Vec2( x, y );
    }

    static calculatePoint(
        startPoint: { x: number; y: number },
        endPoint: { x: number; y: number },
        height: number,
        progress: number
    ): { x: number; y: number } {
        if (progress < 0) progress = 0;
        if (progress > 1) progress = 1;

        // 计算中间控制点（顶点）
        const controlX = (startPoint.x + endPoint.x) / 2;
        const controlY = Math.min(startPoint.y, endPoint.y) - Math.abs(height);

        // 使用二次贝塞尔曲线公式计算坐标
        const x = this.calculateBezier(startPoint.x, controlX, endPoint.x, progress);
        const y = this.calculateBezier(startPoint.y, controlY, endPoint.y, progress);

        return { x, y };
    }

    /**
     * 计算二次贝塞尔曲线点
     * @param p0 起始点
     * @param p1 控制点
     * @param p2 结束点
     * @param t 进度 (0-1)
     * @private
     */
    private static calculateBezier(p0: number, p1: number, p2: number, t: number): number {
        return (1 - t) * (1 - t) * p0 + 2 * (1 - t) * t * p1 + t * t * p2;
    }

    /**
     * 计算抛物线最高点
     * @param startPoint 起始点
     * @param endPoint 结束点
     * @param height 抛物线高度 (绝对值)
     * @returns 最高点坐标
     */
    static calculatePeakPoint_vec2(
        startPoint : Vec2,
        endPoint : Vec2,
        height: number
    ): Vec2 {
        // 顶点在中间
        const x = (startPoint.x + endPoint.x) / 2;
        const y = Math.min(startPoint.y, endPoint.y) - Math.abs(height);
        return new Vec2( x, y );
    }

    static calculatePeakPoint(
        startPoint: { x: number; y: number },
        endPoint: { x: number; y: number },
        height: number
    ): { x: number; y: number } {
        // 顶点在中间
        const x = (startPoint.x + endPoint.x) / 2;
        const y = Math.min(startPoint.y, endPoint.y) - Math.abs(height);
        return { x, y };
    }

    /**
     * 生成抛物线轨迹点数组
     * @param startPoint 起始点
     * @param endPoint 结束点
     * @param height 抛物线高度 (绝对值)
     * @param pointCount 点的数量
     * @returns 轨迹点数组
     */
    static generatePath(
        startPoint: { x: number; y: number },
        endPoint: { x: number; y: number },
        height: number,
        pointCount: number = 20
    ): Array<{ x: number; y: number }> {
        const points: Array<{ x: number; y: number }> = [];
        for (let i = 0; i <= pointCount; i++) {
            const progress = i / pointCount;
            points.push(this.calculatePoint(startPoint, endPoint, height, progress));
        }
        return points;
    }

    static generatePath_vec2(
        startPoint : Vec2,
        endPoint : Vec2,
        height : number,
        pointCount : number = 20
    ): Array<Vec2> {
        const points: Array<Vec2> = [];
        for (let i = 0; i <= pointCount; i++) {
            const progress = i / pointCount;
            points.push(this.calculatePoint_vec2(startPoint, endPoint, height, progress));
        }
        return points;
    }

    /**
     * 根据起始速度计算抛物线轨迹, 水平方向，不考虑空气阻力
     * @param startPoint 起始点
     * @param velocity 初始速度 (包含x和y分量) 
     * @param time 当前时间
     * @returns 当前时间点的坐标
     */
    static calculatePointWithVelocity(
        startPoint: { x: number; y: number },
        velocity: { x: number; y: number },
        time: number
    ): { x: number; y: number } {
        const x = startPoint.x + velocity.x * time;
        const y = startPoint.y + velocity.y * time + 0.5 * HYXH_GRAVITY * time * time;
        return { x, y };
    }
    static calculatePointWithVelocity_vec2(
        startPoint: Vec2,
        velocity: Vec2,
        time: number
    ): Vec2 {
        const x = startPoint.x + velocity.x * time;
        const y = startPoint.y + velocity.y * time + 0.5 * HYXH_GRAVITY * time * time;
        return new Vec2( x, y );
    }
    /**
     * 
     * @param startPoint 起始点
     * @param velocity  初始速度 (包含x和y分量)
     * @param gravity   重力加速度 (默认为9.8，y轴正方向)
     * @param time      当前时间 
     * @returns 
     */
    static calculatePointWithVelocityforOtherEarth(
        startPoint: { x: number; y: number },
        velocity: { x: number; y: number },
        gravity : number,
        time: number
    ): { x: number; y: number } {
        const x = startPoint.x + velocity.x * time;
        const y = startPoint.y + velocity.y * time + 0.5 * gravity * time * time;
        return { x, y };
    }
    static calculatePointWithVelocityOtherEarth_vec2(
        startPoint: Vec2,
        velocity: Vec2,
        gravity : number,
        time: number
    ): Vec2 {
        const x = startPoint.x + velocity.x * time;
        const y = startPoint.y + velocity.y * time + 0.5 * gravity * time * time;
        return new Vec2( x, y );
    }
    /**
     * 计算水平出发初速seSpeed情况下按照于水平方向夹角抛射的抛物的轨迹
     * @param startPoint 起始点位置坐标
     * @param seSpeed    初始速度，计量为M/S
     * @param angle      以屏幕从左往右为正向量即X轴，物体运行的初始行经方向与X轴的夹角
     * @param time       时间是秒
     * @returns 
     */
    static calculatePointWithVelocityAngle(
        startPoint: { x: number; y: number },
        seSpeed: number,
        angle : number,
        time: number
    ): { x: number; y: number } {
        const x_speed = seSpeed * Math.cos(angle);
        const y_speed = seSpeed * Math.sin(angle);
        const x = startPoint.x + x_speed * time;
        const y = startPoint.y + y_speed * time + 0.5 * HYXH_GRAVITY * time * time;
        return { x, y };
    }
    /**
     * 
     * @param startPoint 
     * @param seSpeed 
     * @param angle 
     * @param time 
     * @returns 
     */
    static calculatePointWithVelocityAngle_vec2(
        startPoint: Vec2,
        seSpeed: number,
        angle : number,
        time: number
    ): Vec2 {
        const x_speed = seSpeed * Math.cos(angle);
        const y_speed = seSpeed * Math.sin(angle);
        const x = startPoint.x + x_speed * time;
        const y = startPoint.y + y_speed * time + 0.5 * HYXH_GRAVITY * time * time;
        return new Vec2( x, y );
    }
    /**
     * 计算水平出发初速seSpeed情况下按照于水平方向夹角抛射的抛物的轨迹
     * @param startPoint 起始点位置坐标
     * @param seSpeed    初始速度，计量为M/S
     * @param angle      以屏幕从左往右为正向量即X轴，物体运行的初始行经方向与X轴的夹角
     * @param time       时间是秒
     * @returns 
     */
    static calculatePointWithVelocityAngleOtherEarth(
        startPoint: { x: number; y: number },
        seSpeed: number,
        angle : number,
        gravity : number,
        time: number
    ): { x: number; y: number } {
        const x_speed = seSpeed * Math.cos(angle);
        const y_speed = seSpeed * Math.sin(angle);
        const x = startPoint.x + x_speed * time;
        const y = startPoint.y + y_speed * time + 0.5 * gravity * time * time;
        return { x, y };
    }
    /**
     * 
     * @param startPoint 
     * @param seSpeed 
     * @param angle 
     * @param time 
     * @returns 
     */
    static calculatePointWithVelocityAngleOtherEarth_vec2(
        startPoint: Vec2,
        seSpeed: number,
        angle : number,
        gravity : number,
        time: number
    ): Vec2 {
        const x_speed = seSpeed * Math.cos(angle);
        const y_speed = seSpeed * Math.sin(angle);
        const x = startPoint.x + x_speed * time;
        const y = startPoint.y + y_speed * time + 0.5 * gravity * time * time;
        return new Vec2( x, y );
    }
    /* 支持动画，用于射箭，浇花，水溅洒特效， 用于进行按照1秒30帧的速率进行 */
  
}
